import datetime
import enum
import uuid

from sqlalchemy import Column, Integer, String, ForeignKey, Boolean, Enum, DateTime
from sqlalchemy import desc
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship

from database import Base


class Role(str, enum.Enum):
    User = "user"
    Admin = "admin"
    Alexander = "alexander"


class Status(str, enum.Enum):
    Open = "open"
    InProgress = "in_progress"
    Closed = "closed"

    def with_time(self):
        return StatusWithTime(status=self, datetime=datetime.datetime.now(), is_current=True)


class StatusWithTime(Base):
    __tablename__ = "statuses"
    id = Column(Integer, primary_key=True)
    status = Column(Enum(Status), nullable=False)
    datetime = Column(DateTime(timezone=True), nullable=False)
    is_current = Column(Boolean, nullable=False)
    request_id = Column(Integer, ForeignKey('requests.id'), nullable=False)

    request = relationship("Request", back_populates="statuses", uselist=False)


class User(Base):
    __tablename__ = 'users'
    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    name = Column(String, nullable=False, unique=True)
    email = Column(String, nullable=False, unique=True)
    password = Column(String, nullable=False)
    role = Column(Enum(Role), nullable=False)
    is_verified = Column(Boolean, nullable=False)
    organization_id = Column(Integer, ForeignKey('organizations.id'), nullable=False)

    code = relationship("RandomCode", back_populates="user", uselist=False)
    organization = relationship("Organization", back_populates="users", uselist=False)
    requests = relationship("Request", back_populates="user")
    responses = relationship("Response", back_populates="user")


class Request(Base):
    __tablename__ = 'requests'
    id = Column(Integer, primary_key=True)
    topic = Column(String, nullable=False)
    description = Column(String, nullable=False)
    user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=False)

    current_status = relationship("StatusWithTime", back_populates="request",
                                  order_by=desc(StatusWithTime.id), uselist=False, viewonly=True)
    statuses = relationship("StatusWithTime", back_populates="request", lazy='selectin')
    user = relationship("User", back_populates="requests", uselist=False)
    response = relationship("Response", back_populates="request", uselist=False)


class Response(Base):
    __tablename__ = 'responses'

    id = Column(Integer, primary_key=True)
    description = Column(String, nullable=False)
    user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=False)
    request_id = Column(Integer, ForeignKey('requests.id'), nullable=False)

    user = relationship("User", back_populates="responses", uselist=False)
    request = relationship("Request", back_populates="response", uselist=False)


class Organization(Base):
    __tablename__ = 'organizations'
    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False, unique=True)
    inn = Column(String(length=10), nullable=False, unique=True)

    users = relationship("User", back_populates="organization")


class RandomCode(Base):
    __tablename__ = 'codes'
    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    user_id = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=False)

    user = relationship("User", back_populates="code", uselist=False)
